package com.springmvc.netty;

import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.corundumstudio.socketio.AckRequest;
import com.corundumstudio.socketio.AuthorizationListener;
import com.corundumstudio.socketio.BroadcastOperations;
import com.corundumstudio.socketio.Configuration;
import com.corundumstudio.socketio.HandshakeData;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.listener.ConnectListener;
import com.corundumstudio.socketio.listener.DataListener;
import com.corundumstudio.socketio.listener.DisconnectListener;
import com.springmvc.netty.client.NettyClients;
import com.springmvc.netty.command.Command;
import com.springmvc.netty.exception.BeiMiExceptionListener;
import com.springmvc.netty.invote.ActionMapUtil;
import com.springmvc.netty.server.NettySocketIO;
import com.springmvc.netty.server.UserClient;
import com.springmvc.utils.result.Result;
import com.springmvc.web.majiang.entity.Room;
import com.springmvc.web.majiang.entity.User;
import com.springmvc.web.majiang.service.IRoomService;
import com.springmvc.web.majiang.service.IUserService;

@Component
public class NettySocketServer {

	@Autowired
	IUserService				userService;

	@Autowired
	IRoomService				roomService;

	private static final Logger	logger = LoggerFactory.getLogger(BeiMiExceptionListener.class);

	@Value("${netty-socketio.host}")
	private String				host;

	@Value("${netty-socketio.port}")
	private Integer				port;

	@Value("${netty-socketio.threads}")
	private String				threads;

	private SocketIOServer		server;

	//	private SocketIONamespace	gameSocketNameSpace;

	@PostConstruct
	public void socketIOServer() throws NoSuchAlgorithmException, IOException {

		Configuration config = new Configuration();
		config.setHostname(host);
		config.setPort(port);

		//		config.getSocketConfig().setReuseAddress(true);
		//		config.setSocketConfig(new SocketConfig());
		//		config.setOrigin("http://im.uckefu.com");

		config.setExceptionListener(new BeiMiExceptionListener());

		int workThreads = !StringUtils.isBlank(threads) && threads.matches("[\\d]{1,6}") ? Integer.parseInt(threads)
				: 100;
		config.setWorkerThreads(workThreads);

		//		config.setStoreFactory(new HazelcastStoreFactory());
		config.setAuthorizationListener(new AuthorizationListener() {

			@Override
			public boolean isAuthorized(HandshakeData data) {

				//				String username = data.getSingleUrlParam("username");
				//				String password = data.getSingleUrlParam("password");
				//				System.err.println(username);
				return true; //其他安全验证策略，IP，Token，用户名
			}
		});

		//		SocketIONamespace newChatnsp = server.addNamespace("123123"); //设置命名空间  
		/**
		 * 性能优化
		 */
		config.getSocketConfig().setReuseAddress(true);
		config.getSocketConfig().setSoLinger(0);
		config.getSocketConfig().setTcpNoDelay(true);
		config.getSocketConfig().setTcpKeepAlive(true);

		server = new SocketIOServer(config);

		//		final SocketIONamespace chat1namespace = server.addNamespace("/majiang");

		// 握手请求
		server.addEventListener(NettySocketIO.MJ, HashMap.class, new DataListener<HashMap>() {

			@Override
			public void onData(final SocketIOClient client, HashMap data, AckRequest ackRequest) {
				//				server.getBroadcastOperations().sendEvent(NettySocketIO.MJ, data);
				try {
					ActionMapUtil.invote(Command.valueOf(String.valueOf(data.get("command"))), server, client, data,
							ackRequest);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});

		//添加客户端连接事件
		server.addConnectListener(new ConnectListener() {

			@Override
			public void onConnect(SocketIOClient client) {
				// TODO Auto-generated method stub
				String sa = client.getRemoteAddress().toString();
				String clientIp = sa.substring(1, sa.indexOf(":"));//获取设备ip
				logger.info(clientIp + "-------------------------" + "客户端已连接");
				HandshakeData params = client.getHandshakeData();

				//获取客户端连接的uuid参数
				String userid = params.getSingleUrlParam("userid");
				String roomid = params.getSingleUrlParam("roomid");
				if (StringUtils.isBlank(userid) || StringUtils.isBlank(roomid)) {
					client.sendEvent(NettySocketIO.MJ, Result.ERROR(Command.e9999, "参数错误"));
					return;
				}
				User user = userService.selectById(Long.valueOf(userid));
				if (user == null) {
					client.sendEvent(NettySocketIO.MJ, Result.ERROR(Command.e9999, "用户不存在"));
					return;
				}
				Room room = roomService.selectById(Long.valueOf(roomid));
				if (room == null) {
					client.sendEvent(NettySocketIO.MJ, Result.ERROR(Command.e9999, "房间不存在"));
					return;
				}
				UserClient userClient = new UserClient();
				userClient.setClient(client);
				userClient.setUserid(userid);
				//缓存SocketIOClient
				NettyClients.getInstance().putClient(client.getSessionId().toString(), userClient);
				//分配用到房间
				NettyClients.getInstance().joinRoom(client.getSessionId().toString(), roomid);

				//给客户端发送消息
				Map<String, String> data = new HashMap<String, String>();
				data.put("username", user.getUsername());
				data.put("address", client.getRemoteAddress().toString());
				data.put("msg", "进入房间");
				BroadcastOperations broadcastOperations = server.getRoomOperations(roomid);
				broadcastOperations.sendEvent(NettySocketIO.MJ, client, Result.SUCCESS(Command.s8888, data));
				client.sendEvent(NettySocketIO.MJ, Result.MSG(Command.s8888, "客户端你好，我是服务端，有什么能帮助你的？"));
			}
		});
		//添加客户端断开连接事件
		server.addDisconnectListener(new DisconnectListener() {

			@Override
			public void onDisconnect(SocketIOClient client) {
				String sa = client.getRemoteAddress().toString();
				String clientIp = sa.substring(1, sa.indexOf(":"));//获取设备ip
				logger.info(clientIp + "-------------------------" + "客户端已断开连接");
				//给客户端发送消息
				client.sendEvent(NettySocketIO.MJ, Result.MSG(Command.s8888, "客户端你好，我是服务端，期待下次和你见面"));
				NettyClients.getInstance().removeClient(client.getSessionId().toString());
			}
		});

		server.start();
	}

	@PreDestroy
	public void destory() {
		server.stop();
	}
}